package cn.cosmosx.base.encrypt.jwt;

import cn.cosmosx.base.constant.ResultCode;
import cn.cosmosx.base.encrypt.hex.HexUtil;
import cn.cosmosx.base.exception.PlatformException;
import com.google.gson.GsonBuilder;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.gson.io.GsonDeserializer;
import io.jsonwebtoken.gson.io.GsonSerializer;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Calendar;
import java.util.Collections;
import java.util.Map;

/**
 * JWTs工具类
 * 基于 io.jsonwebtoken
 */
@Slf4j
public final class JWTsUtil {
    /**
     * jwt加密算法
     */
    private final static SignatureAlgorithm ALGORITHM = SignatureAlgorithm.HS512;

    /**
     * 加密秘钥的base64串
     * 注：若采用{@linkplain SignatureAlgorithm#HS512}算法，则加密秘钥的base64串解密之后的字符数最低要求为 64(512/8) 个
     */
    private final static String PRIVATE_KEY = "spring@spring-boot-security@Jwt@Project-QuickSand@Author-gengzhy";
    /**
     * 签发人
     */
    private final static String ISSUER = "gengzhy";

    /**
     * 由字符串生成加密key
     *
     * @return - SecretKey
     */
    public static Key generalKey() {
        // 本地的密码解码
        byte[] decodeKey = HexUtil.encode(PRIVATE_KEY.getBytes(StandardCharsets.UTF_8));
        // 根据给定的字节数组使用AES加密算法构造一个密钥
        return new SecretKeySpec(decodeKey, 0, decodeKey.length, ALGORITHM.getJcaName());
    }

    /**
     * 创建JWT Token
     *
     * @param id - 唯一标识（用户id等）
     */
    public static String token(String id) {
        return token(id, null);
    }

    /**
     * 创建JWT Token
     *
     * @param id     - 唯一标识（用户id等）
     * @param claims - 自定义属性
     */
    public static String token(String id, Map<String, Object> claims) {
        try {
            return Jwts.builder()
                    .serializeToJsonWith(new GsonSerializer<>(new GsonBuilder().disableHtmlEscaping().create()))
                    .setHeaderParam("typ", "JWT")
                    .setSubject(id)
                    .setId(id)
                    .setIssuer(ISSUER)
                    .setIssuedAt(Calendar.getInstance().getTime())
                    .signWith(generalKey())
                    .addClaims(claims == null ? Collections.emptyMap() : claims)// 勿用setClaims，否则会覆盖前面所有数据
                    .compact();
        } catch (JwtException e) {
            log.error("Token生成失败", e);
            throw new PlatformException("Token生成失败");
        }
    }

    /**
     * token解析
     *
     * @param token - jwt
     * @return
     */
    public static Claims parseJwt(String token) {
        Claims body;
        try {
            body = Jwts.parserBuilder() // 得到DefaultJwtParser
                    .deserializeJsonWith(new GsonDeserializer<>(new GsonBuilder().disableHtmlEscaping().create()))
                    .setSigningKey(generalKey()) // 设置签名的秘钥
                    .build()
                    .parseClaimsJws(token).getBody();
        } catch (SecurityException e) {
            log.error("token解析异常", e);
            throw new PlatformException(ResultCode.E00005);
        }
        return body;
    }
}
